#include <windows.h>
#include <stdio.h>

#define MAX_LOADSTRING 100

#define WM_MANILA_TODAY_TAB_TERMINATE WM_USER + 24

#define MANILA_TODAY_TIMER 1

//#define MANILA2D 1

#ifndef MANILA2D
	const TCHAR* ManilaWindowName = L"Manila";
#else
	const TCHAR* ManilaWindowName = L"HTCManila2D";
#endif

// Global Variables:
HINSTANCE			g_hInst;			// current instance

// Forward declarations of functions included in this code module:
ATOM			MyRegisterClass(HINSTANCE, LPTSTR);
BOOL			InitInstance(HINSTANCE, int);
LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);

void LoadManila(HWND hWnd, bool isManual);


typedef struct _CALLBACKINFO {
    HANDLE  hProc;      /* destination process */
    FARPROC pfn;        /* function to call in dest. process */
    PVOID   pvArg0;     /* arg0 data */
} CALLBACKINFO;
typedef CALLBACKINFO *PCALLBACKINFO;

extern"C" LPVOID MapPtrToProcess(LPVOID lpv, HANDLE hProc);
extern"C" DWORD PerformCallBack4(CALLBACKINFO *pcbi);

void FormatSpecialFolderPath(int nFolder, const LPTSTR path, LPTSTR result)
{	
	TCHAR FolderPath[MAX_PATH];
	SHGetSpecialFolderPath(0, FolderPath, nFolder, 1);
	if (FolderPath[wcslen(FolderPath) - 1] == '\\')
	{
		wsprintf(result, L"%s%s", FolderPath, path); 
	}
	else
	{
		wsprintf(result, L"%s\\%s", FolderPath, path); 
	}
}

TCHAR lpCmdLine[MAX_PATH];

int WINAPI WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPTSTR    lpCmdLineO,
                   int       nCmdShow)
{
	MSG msg;

	wcsncpy(lpCmdLine, lpCmdLineO, MAX_PATH);

	if (!InitInstance(hInstance, nCmdShow)) 
	{
		return FALSE;
	}

	while (GetMessage(&msg, NULL, 0, 0)) 
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return (int) msg.wParam;
}

//
//  FUNCTION: MyRegisterClass()
//
//  PURPOSE: Registers the window class.
//
//  COMMENTS:
//
ATOM MyRegisterClass(HINSTANCE hInstance, LPTSTR szWindowClass)
{
	WNDCLASS wc;

	wc.style         = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc   = WndProc;
	wc.cbClsExtra    = 0;
	wc.cbWndExtra    = 0;
	wc.hInstance     = hInstance;
	wc.hIcon         = 0;
	wc.hCursor       = 0;
	wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
	wc.lpszMenuName  = 0;
	wc.lpszClassName = szWindowClass;

	return RegisterClass(&wc);
}

//
//   FUNCTION: InitInstance(HINSTANCE, int)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
    HWND hWnd;
    TCHAR szTitle[MAX_LOADSTRING];		// title bar text
    TCHAR szWindowClass[MAX_LOADSTRING];	// main window class name
	
	wcscpy(szTitle, L"MTP Loader Titile.");
	wcscpy(szWindowClass, L"MTPLoaderWC");

    g_hInst = hInstance; // Store instance handle in our global variable

    //If it is already running, then ask for termination
    hWnd = FindWindow(szWindowClass, szTitle);	
    if (hWnd) 
    {
        if (MessageBox(0, L"MTP is already loaded. Terminate?", L"Manila Today Page", MB_YESNO) == IDYES)
		{
			PostMessage(hWnd, WM_MANILA_TODAY_TAB_TERMINATE, 0, 0);
		}
        return 0;
    } 

    if (!MyRegisterClass(hInstance, szWindowClass))
    {
    	return FALSE;
    }

    hWnd = CreateWindow(szWindowClass, szTitle, WS_VISIBLE,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
	
	ShowWindow(hWnd, SW_HIDE);

    if (!hWnd)
    {
        return FALSE;
    }

	LoadManila(hWnd, wcsicmp(L"/boot", lpCmdLine));

	SetTimer(hWnd, MANILA_TODAY_TIMER, 1000, 0);

    return TRUE;
}

void LoadManila(HWND hWnd, bool isInteractive)
{
	HWND wnd = 0;
	int cnt = 0;
	do
	{
		wnd = FindWindow (ManilaWindowName, 0);
		if (!wnd)
			Sleep(3000);
		cnt++;

		if (cnt > 60)
		{
			MessageBox(0,  L"Unable to find Manila :(", L"Manila Today Page", MB_ICONERROR);
			DestroyWindow(hWnd);
			return;
		}
	}
	while (!wnd);

	DWORD processId;
	GetWindowThreadProcessId(wnd, &processId);

	TCHAR dllPath[MAX_PATH];
	FormatSpecialFolderPath(CSIDL_PROGRAM_FILES, L"\\ManilaTodayPage\\HookDLL.dll", dllPath);
	int dataLen = wcslen(dllPath) + 1;

	HANDLE Proc = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE, false, processId);

	void *Ptr= MapPtrToProcess(dllPath, GetCurrentProcess());
	CALLBACKINFO ci;

	ci.hProc=Proc;
	void *t=GetProcAddress(GetModuleHandle(L"coredll.dll"),L"LoadLibraryW");

	ci.pfn=(FARPROC)MapPtrToProcess(t,Proc);
	ci.pvArg0=Ptr;

	HINSTANCE hInst = (HINSTANCE)PerformCallBack4(&ci);

	FARPROC pHook = GetProcAddress(hInst, (LPWSTR )1);
	ci.hProc = Proc;
	ci.pfn = (FARPROC)MapPtrToProcess(pHook, Proc);
	ci.pvArg0 = NULL; //here we can pass any argument for our 'ExportedFunction'
	DWORD dw = PerformCallBack4(&ci);//returns the same value of 'ExportedFunction'

	CloseHandle(Proc);
	
	if (isInteractive)
		MessageBox(0, L"Load Complete", L"Manila Today Page", 0);

}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message) 
    {
        case WM_TIMER:
			{
				HANDLE existing = OpenEvent(EVENT_ALL_ACCESS, false, L"ManilaTodayPageStartup");
				if (existing)
				{
					CloseHandle(existing);
				}
				else
				{
					LoadManila(hWnd, false);
					// wait 5 sec before new checks
					Sleep(5000);
				}
			}
            break;
		
		case WM_DESTROY:
		case WM_MANILA_TODAY_TAB_TERMINATE:
			{
				KillTimer(hWnd, MANILA_TODAY_TIMER);
				HWND wnd = FindWindow (ManilaWindowName, 0);
				PostMessage(wnd, WM_MANILA_TODAY_TAB_TERMINATE, 0, 0);
				PostQuitMessage(0);
			}
			break;

        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}
